#ifndef __MY_LOG_LOOPER__
#define __MY_LOG_LOOPER__
#include<mutex>
#include<condition_variable>
#include"buffer.hpp"
#include<functional>
#include<thread>
#include <atomic>
namespace mylog
{
    using Functor = std::function<void(Buffer&)>;
    enum class AsyncType{
        ASYNC_SAFE,
        ASYNC_UNSAFE
    };
    class Asynclooper
    {
        public:
            using ptr = std::shared_ptr<Asynclooper>;
            Asynclooper(Functor cb, AsyncType type = AsyncType::ASYNC_SAFE)
            :_stop(false),
            _callback(cb),
            _thread(std::thread(&Asynclooper::threadEntry,this)),
            _type(type)
            {
            }
            ~Asynclooper()
            {
                stop();
            }
            void stop()
            {
                _stop = true;
                _cond_con.notify_all();
                _thread.join();

            }
            void push(const char* data,size_t len)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                if(_type == AsyncType::ASYNC_SAFE)
                {
                    _cond_pro.wait(lock,[&](){ return _ibuf.WriteAbleSIze() >= len;});
                }
                _ibuf.push(data,len);
                _cond_con.notify_one();

            }
        public:
            void threadEntry()
            {
                while(!_stop || (_stop && !_ibuf.empty()))
                {
                    {
                        std::unique_lock<std::mutex> lock(_mutex);
                        _cond_con.wait(lock, [&](){ return _stop == true || !_ibuf.empty();});
                        _obuf.swap(_ibuf);
                        if(_type == AsyncType::ASYNC_SAFE)
                        {
                            _cond_pro.notify_all();
                        }

                    }
                    _callback(_obuf);

                    _obuf.reset();
                }
            }
        private:
            Functor _callback;
        private:
            AsyncType _type;
            std::mutex _mutex;
            Buffer _ibuf;
            Buffer _obuf;
            std::condition_variable _cond_con;
            std::condition_variable _cond_pro;
            std::thread _thread;
            std::atomic<bool> _stop;


    };
} // namespace mylog


#endif